/**
 * 4.[Browser part]: Jet.dom 扩展包
 */
Jet().$package(function(J){
	var $D,
		$B,
		id,
		name,
		tagName,
		getText,
		getAttributeByParent,
		node,
		textNode,
		setClass,
		getClass,
		hasClass,
		addClass,
		removeClass,
		toggleClass,
		replaceClass,
		setStyle,
		getStyle,
		setCssText,
		getCssText,
		addCssText,
		show,
		isShow,
		recover,
		hide,
		remove,
		html,
		text,
		empty,
		prepend,
		append,
		html2dom,
		
		getScrollHeight,
		getScrollWidth,
		getClientHeight,
		getClientWidth,
		getOffsetHeight,
		getOffsetWidth,
		
		getScrollLeft,
		getScrollTop,
		getClientXY,
		setClientXY,
		getXY,
		setXY,
		getRelativeXY,
		
		getSelection,
		getSelectionText,
		getTextFieldSelection,
		
	
		getDoc,
		getWin,
		w,
		getDocumentElement,
		getBodyElement;
	/**
	 * dom 名字空间
	 * 
	 * @namespace
	 * @name dom
	 * @type Object
	 */
	J.dom = J.dom || {};
	$D = J.dom;
	$B = J.browser;
	
		

	// find targeted window and @TODO create facades
	w = ($D.win) ? ($D.win.contentWindow) : $D.win  || window;
	$D.win = w;
	$D.doc = w.document;
	
	/**
	 * 获取DocumentElement
	 * 
	 * @memberOf dom
	 */
	getDocumentElement = function(){
		if(document.compatMode === 'CSS1Compat'){
			return document.documentElement;
		}else{
			return document.body;
		}
		
	};
	
	/**
	 * 获取HTMLBodyElement
	 * 
	 * @memberOf dom
	 */
	getBodyElement = function() {
		var elem = getDocumentElement();
		if(elem.tagName=='BODY') return elem;
		var aElem = tagName('body');
		if(aElem.length > 0) return aElem[0];
		return null;
	}
	
	/**
	 * 获取元素所属的根文档
	 * 
	 * @memberOf dom
	 */
	getDoc = function(element) {
		element = element || window.document;
		return (element["nodeType"] === 9) ? element : element["ownerDocument"]
			|| $D.doc;
	};
	
	/**
	 * 获取元素所属的 window 对象
	 * returns the appropriate window.
	 * 
	 * @memberOf dom
	 * @private
	 * @param {HTMLElement} element optional Target element.
	 * @return {Object} The window for the given element or the default window. 
	 */
	getWin = function(element) {
		var doc = getDoc(element);
		return (element.document) ? element : doc["defaultView"] ||
			doc["parentWindow"] || $D.win;
	};
	
	/**
	 * 
	 * 根据 id 获取元素
	 * 
	 * @method id
	 * @memberOf dom
	 * 
	 * @param {String} id 元素的 id 名称
	 * @param {Element} doc 元素所属的文档对象，默认为当前文档
	 * @return {Element} 返回元素
	 * 
	 * @example
	 * 
	 * 
	 */
	id = function(id, doc) {
		return getDoc(doc).getElementById(id);
	};
	
	/**
	 * 
	 * 根据 name 属性获取元素
	 * 
	 * @memberOf dom
	 * 
	 * @param {String} name 元素的 name 属性
	 * @param {Element} doc 元素所属的文档对象，默认为当前文档
	 * @return {Element} 返回元素
	 */
	name = function(name, doc) {
		//var el = doc;
		return getDoc(doc).getElementsByName(name);
	};
	
	/**
	 * 
	 * 根据 tagName 获取元素
	 * 
	 * @memberOf dom
	 * 
	 * @param {String} tagName 元素的 tagName 标签名
	 * @param {Element} doc 元素所属的文档对象，默认为当前文档
	 * @return {Element} 返回元素
	 */
	tagName = function(tagName, el) {
		var el = el || getDoc();
		return el.getElementsByTagName(tagName);
	};
	
	/**
	 * 获取元素中的文本内容
	 * Returns the text content of the HTMLElement. 
	 * 
	 * @memberOf dom
	 * @param {HTMLElement} element The html element. 
	 * @return {String} The text content of the element (includes text of any descending elements).
	 */
	getText = function(element) {
		var text = element ? element[TEXT_CONTENT] : '';
		if (text === UNDEFINED && INNER_TEXT in element) {
			text = element[INNER_TEXT];
		} 
		return text || '';
	};
	
	
	/**
	 * 从起始元素查找某个属性，直到找到，或者到达顶层元素位置
	 * Returns the text content of the HTMLElement. 
	 * 
	 * @memberOf dom
	 * @param {HTMLElement} element The html element. 
	 * @return {String} The text content of the element (includes text of any descending elements).
	 */
	getAttributeByParent = function(attribute, startNode,  topNode){
		var jumpOut = false;
		var el = startNode;
		var result;
		do{
			result = el.getAttribute(attribute);
			// 如果本次循环未找到result
			if(J.isUndefined(result) || J.isNull(result)){
				// 如果本次循环已经到了监听的dom
				if(el === topNode){
					jumpOut = true;
				}
				// 如果本次循环还未到监听的dom，则继续向上查找
				else {
					el = el.parentNode;
				}
			}
			// 如果找到了result
			else{
				jumpOut = true;
			}
		}
		while(!jumpOut);
		
		return result;
	};
	
	
	/** 
	 * 生成一个 DOM 节点
     * Generates an HTML element, this is not appended to a document
     * 
     * @memberOf dom
     * 
     * @param type {string} the type of element
     * @param attr {string} the attributes
     * @param win {Window} optional window to create the element in
     * @return {HTMLElement} the generated node
     */
    node = function(type, attrObj, win){
        var p,
        	w = win || $D.win,
        	d = w.document,
        	n = d.createElement(type);

        for (p in attrObj) {
        	var mapObj = {
        		"class":function(){
        			n.className = attrObj[p];
        		}
        	}
			if(mapObj[p]){
				mapObj[p]();
			}else{
				n.setAttribute(p, attrObj[p]);
			}
        }

        return n;
    };
    
    
    /** 
	 * 生成一个 TEXT 节点
     * 
     * @memberOf dom
     * 
     * @param text {string} text
     * @param win {Window} optional window to create the element in
     * @return {HTMLElement} the generated node
     */
    textNode = function(text, win){
    	var w = win || $D.win,
    		d = w.document;
    	return d.createTextNode(text);
    }


	/**
	 * 获取文档的 scroll 高度，即文档的实际高度
     * Returns the height of the document.
     * 
     * @method getDocumentHeight
     * @memberOf dom
     * 
     * @param {HTMLElement} element The html element. 
     * @return {Number} The height of the actual document (which includes the body and its margin).
     */
    getScrollHeight = function(el) {
        var scrollHeight;
    	if(el){
    		scrollHeight = el.scrollHeight;
    	}else{
    		scrollHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
    	}
        return scrollHeight || 0;
    };
    
    /**
     * 获取文档的 scroll 宽度，即文档的实际宽度
     * Returns the width of the document.
     * 
     * @method getDocumentWidth
     * @memberOf dom
     * 
     * @param {HTMLElement} element The html element. 
     * @return {Int} The width of the actual document (which includes the body and its margin).
     */
    getScrollWidth = function(el) {
        var scrollWidth;
    	if(el){
    		scrollWidth = el.scrollWidth;
    	}else{
    		scrollWidth = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth);
    	}
        return scrollWidth || 0;
    };

    /**
     * 获取当前视窗的高度
     * Returns the current height of the viewport.
     * 
     * @method getClientHeight
     * @memberOf dom
     * @return {Int} The height of the viewable area of the page (excludes scrollbars).
     */
    getClientHeight = function(el) {
    	//var name = J.browser.engine.name;
    	el = el || getDocumentElement();
    	return el.clientHeight; // IE, Gecko
    };
    
    /**
     * 获取元素的client宽度
     * Returns the current width of the viewport.
     * @method getClientWidth
     * @memberOf dom
     * @param {Element} el 要获取client宽度的元素
     * @return {Number} 宽度值.
     */
    
    getClientWidth = function(el) {
    	//var name = J.browser.engine.name;
    	el = el || getDocumentElement();
    	return el.clientWidth; // IE, Gecko
    };
    
    
    /**
     * 获取当前视窗的高度
     * Returns the current height of the viewport.
     * 
     * @method getOffsetHeight
     * @memberOf dom
     * @return {Int} The height of the viewable area of the page (excludes scrollbars).
     */
    getOffsetHeight = function(el) {
    	//var name = J.browser.engine.name;
    	el = el || getDocumentElement();
    	return el.offsetHeight; 
    };
    
    /**
     * 获取元素的client宽度
     * Returns the current width of the viewport.
     * @method getOffsetWidth
     * @memberOf dom
     * @param {Element} el 要获取client宽度的元素
     * @return {Number} 宽度值.
     */
    getOffsetWidth = function(el) {
    	//var name = J.browser.engine.name;
    	el = el || getDocumentElement();
    	return el.offsetWidth;
    };
    
    /**
     * 获取当前文档的左边已卷动的宽度
     * Returns the left scroll value of the document 
     * @method getDocumentScrollLeft
     * @memberOf dom
     * @param {HTMLDocument} document (optional) The document to get the scroll value of
     * @return {Int}  The amount that the document is scrolled to the left
     */
    getScrollLeft = function(el) {
    	var scrollLeft;
    	if(el){
    		scrollLeft = el.scrollLeft;
    	}else{
    		scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
    	}
        return scrollLeft || 0;
    };

    /**
     * 获取当前文档的上边已卷动的宽度
     * Returns the top scroll value of the document 
     * @method getDocumentScrollTop
     * @memberOf dom
     * @param {HTMLDocument} document (optional) The document to get the scroll value of
     * @return {Int}  The amount that the document is scrolled to the top
     */
    getScrollTop = function(el) {
        var scrollTop;
    	if(el){
    		scrollTop = el.scrollTop;
    	}else{
    		scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
    	}
        return scrollTop || 0;
    };

    
    /**
	 * 
	 * 设置元素的class属性
	 * 
	 * @method setClass
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} className class 名称
	 */
    setClass = function(el, className){
    	el.className = className;
    };
    
    /**
	 * 
	 * 获取元素的class属性
	 * 
	 * @method getClass
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} className class 名称
	 */
    getClass = function(el){
    	return el.className;
    };

    /**
	 * 
	 * 判断元素是否含有 class
	 * 
	 * @method hasClass
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} className class 名称
	 */
    hasClass = function(el, className){
	    var re = new RegExp("(^|\\s)" + className + "(\\s|$)");
	    return re.test(el.className);
	};

	/**
	 * 
	 * 给元素添加 class
	 * 
	 * @method addClass
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} className class 名称
	 */
	addClass = function(el, className){
		if (!hasClass(el, className)){
			el.className = el.className + " " + className;
		}
	};

	/**
	 * 
	 * 给元素移除 class
	 * 
	 * @method addClass
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} className class 名称
	 */
    removeClass = function(el, className){
		el.className = el.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
	};
    
	/*
	removeClass2 = function(el, className){
    	replaceClass(el, className, "");
    };
	*/
    
    
    /**
	 * 
	 * 对元素 class 的切换方法，即：如果元素用此class则移除此class，如果没有此class则添加此class
	 * 
	 * @method toggleClass
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} className class 名称
	 */
    toggleClass = function(el, className){
		return hasClass(el, className) ? removeClass(el, className) : addClass(el, className);
	};

	/**
	 * 
	 * 替换元素 oldClassName 为 newClassName
	 * 
	 * @method toggleClass
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} oldClassName 被替换的 class 名称
	 * @param {String} newClassName 要替换成的 class 名称
	 */
    replaceClass = function(el, oldClassName, newClassName){
    	removeClass(el, oldClassName);
    	addClass(el, newClassName);
    	//el.className = (" "+el.className+" ").replace(" "+oldClassName+" "," "+newClassName+" ");
    };
    /*
    replaceClass2 = function(el, oldClassName, newClassName){
    	var i,
    		tempClassNames = el.className.split(" ");
    		
		for(i=0; i<tempClassNames.length; i++){
			if(tempClassNames[i] === oldClassName){
				tempClassNames[i] = newClassName;
			}
		}
    	//J.out(tempClassNames);

    	el.className = tempClassNames.join(" ");
    };
    */
	
    /**
	 * 
	 * 设置元素的样式，css 属性需要用驼峰式写法，如：fontFamily
	 * 
	 * @method setStyle
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} styleName css 属性名称
	 * @param {String} value css 属性值
	 */
    setStyle = function(el, styleName, value){
		if(!el){
    		return;
    	}
    	
		var name = J.browser.name;
		if(styleName === "float" || styleName === "cssFloat"){
    		if(name === "ie"){
    			styleName = "styleFloat";
    		}else{
    			styleName = "cssFloat";
    		}
    	}    	
    	if(styleName === "opacity" && name === "ie"){
    		
    		el.style.filter = 'alpha(opacity=' + (value*100) + ')';
    		if(!el.style.zoom){
    			el.style.zoom = 1;
    		}
			return;
    	}    	
    	if(styleName === "z-index") styleName = 'zIndex';
    	el.style[styleName] = value;
    };
    
    /**
	 * 
	 * 获取元素的当前实际样式，css 属性需要用驼峰式写法，如：fontFamily
	 * 
	 * @method getStyle
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} styleName css 属性名称
	 * @return {String} 返回元素样式
	 */
    getStyle = function(el, styleName){
    	if(!el){
    		return;
    	}
    	
    	var win = getWin(el);
    	var name = J.browser.name;
    	//J.out(name);
		if(styleName === "float" || styleName === "cssFloat"){
    		if(name === "ie"){
    			styleName = "styleFloat";
    		}else{
    			styleName = "cssFloat";
    		}
    	}
    	if(styleName === "opacity" && name === "ie"){
    		var opacity = 1,
    			result = el.style.filter.match(/opacity=(\d+)/);
    		if(result && result[1]){
    			opacity = result[1]/100;
    		}
			return opacity;
    	}    	
    	if(styleName === "z-index") styleName = 'zIndex';
    	
    	if(el.style[styleName]){
    		return el.style[styleName];
    	}else if(el.currentStyle){
    		//alert(el.currentStyle[styleName]);
    		return el.currentStyle[styleName];
    	}else if(win.getComputedStyle){
    		//J.out(win.getComputedStyle(el, null));
    		return win.getComputedStyle(el, null)[styleName];
    	}else if(document.defaultView && document.defaultView.getComputedStyle){
    		styleName = styleName.replace(/([/A-Z])/g, "-$1");
    		styleName = styleName.toLowerCase();
    		var style = document.defaultView.getComputedStyle(el, "");
    		return style && style.getPropertyValue(styleName);
    	}

    };
    
    
    
    
    /**
	 * 
	 * 给元素添加cssText
	 *  
	 * @method addCssText
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} cssText css 属性
	 */
    addCssText = function(el, cssText){
    	el.style.cssText += ';' + cssText;
    };
    
    /**
	 * 
	 * 给元素设置cssText
	 *  
	 * @method setCssText
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} cssText css 属性
	 */
    setCssText = function(el, cssText){
    	el.style.cssText = cssText;
    };
    /**
	 * 
	 * 获取元素的cssText
	 *  
	 * @method getCssText
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 */
    getCssText = function(el){
    	return el.style.cssText;
    };
    
    /**
	 * 
	 * 显示元素
	 * 
	 * @method show
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 * @param {String} displayStyle 强制指定以何种方式显示，如：block，inline，inline-block等等
	 */
    show = function(el, displayStyle){
    	if(displayStyle){
    		setStyle(el, "display", displayStyle);
    		return;
    	}
    	
    	var _oldDisplay = el.getAttribute("_oldDisplay");
    	var display;
    	if(_oldDisplay){
    		display = _oldDisplay;
    	}else{
    		display = getStyle(el, "display");
    	}	
    	if(display === "none"){
    		setStyle(el, "display", "block");
    	}else{
    		setStyle(el, "display", display);
    	}
    	
    	/*var display;
    	var _oldDisplay = el.getAttribute("_oldDisplay");
    	
    	if(_oldDisplay){
    		display = _oldDisplay;
    	}else{
    		display = getStyle(el, "display");
    	}

    	if(displayStyle){
    		setStyle(el, "display", displayStyle);
    	}else{
	    	if(display === "none"){
	    		setStyle(el, "display", "block");
	    	}else{
	    		setStyle(el, "display", display);
	    	}
    	}*/
    };
    
    /**
	 * 
	 * 判断元素是否是显示状态
	 * 
	 * @method isShow
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 */
    isShow = function(el){
    	var display = getStyle(el, "display");
    	if(display === "none"){
    		return false;
    	}else{
    		return true;
    	}
    };
    
    /**
	 * 
	 * 还原元素原来的display属性
	 * 
	 * @method recover
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 */
    recover = function(el){
    	var display;
    	var _oldDisplay = el.getAttribute("_oldDisplay");
    	
    	if(_oldDisplay){
    		display = _oldDisplay;
    	}else{
    		display = getStyle(el, "display");
    	}
    	if(display === "none"){
    		setStyle(el, "display", "");
    	}else{
    		setStyle(el, "display", display);
    	}
    };
    
    /**
	 * 
	 * 隐藏元素
	 * 
	 * @method hide
	 * @memberOf dom
	 * 
	 * @param {Element} el 元素
	 */
    hide = function(el){
    	var display = getStyle(el, "display");
    	var _oldDisplay = el.getAttribute("_oldDisplay");
    	
    	if(!_oldDisplay){
    		if(display === "none"){
    			el.setAttribute("_oldDisplay", "");
    		}else{
    			el.setAttribute("_oldDisplay", display);
    		}
    	}
    	setStyle(el, "display", "none");
    };
    
    /**
	 * 删除元素
	 * @author solar
	 * @method remove
	 * @memberOf dom
	 * @param {Element} el 元素
	 */
    remove = function(el){
    	el.parentNode.removeChild(el);		
    };
    
    /**
	 * 设置元素的子元素
	 * @author solar
	 * @method html
	 * @memberOf dom
	 * @param {Element} el 元素
	 * @param {Element} node 元素
	 */
    html = function(el, node){
    	empty(el);
    	if(typeof node === "string") el.innerHTML = node;
    	else el.appendChild(node);
    };
    
    /**
	 * 获取或者设置元素的文本
	 * @author solar
	 * @method text
	 * @memberOf dom
	 * @param {Element} elem 元素
	 * @param {String} txt 文本
	 */
    text = function(elem, txt){
    	if(typeof txt === "string"){
    		empty(elem);
    		elem.appendChild($D.doc.createTextNode(txt));
    		return txt;
    	}
    	var nodeType = elem.nodeType,
			ret = "";
    	if ( nodeType === 1 || nodeType === 9 ) {
			// Use textContent || innerText for elements
			if ( typeof elem.textContent === 'string' ) {
				return elem.textContent;
			} else if ( typeof elem.innerText === 'string' ) {
				// Replace IE's carriage returns
				return elem.innerText.replace( rReturn, '' );
			} else {
				// Traverse it's children
				for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
					ret += text( elem );
				}
				return ret;
			}
		} else if ( nodeType === 3 || nodeType === 4 ) {
			return elem.nodeValue;
		}
    	return null;
    };
    
    /**
	 * 清空子元素
	 * @author solar
	 * @method empty
	 * @memberOf dom
	 * @param {Element} el 元素
	 */
    empty = function(el){
    	while (el.firstChild) {
    		el.removeChild(el.firstChild);
		}
    };
	
    /**
	 * 前面附加标签
	 * @author solar
	 * @method prepend
	 * @memberOf dom
	 * @param {Element} el 元素
	 * @param {String} html 标签
	 */
    prepend = function(el,html) {
    	var fragment = $D.doc.createDocumentFragment();
    	html2dom(html,fragment);
    	el.insertBefore(fragment, el.firstChild);
    };
    
    /**
	 * 后面附加标签
	 * @author solar
	 * @method append
	 * @memberOf dom
	 * @param {Element} el 元素
	 * @param {String} html 标签
	 */
    append = function(el,html) {
    	var fragment = $D.doc.createDocumentFragment();
    	html2dom(html,fragment);
    	el.appendChild(fragment);
    };
    
    /**
	 * 标签转换为dom
	 * @author solar
	 * @method html2dom
	 * @memberOf dom
	 * @param {String} html 标签
	 * @param {Element} fragment 文档碎片
	 */
    html2dom = function(html,fragment) {
    	if(typeof html !== "string") return;
    	var d=$D.win.document, ret=[];
    	
    	// Fix "XHTML"-style tags in all browsers
    	html = html.replace(J.rxhtmlTag, "<$1></$2>");

		// Trim whitespace, otherwise indexOf won't work as expected
		var tag = ( J.rtagName.exec( html ) || ["", ""] )[1].toLowerCase(),
			wrap = J.wrapMap[ tag ] || J.wrapMap._default,
			depth = wrap[0],
			div = d.createElement("div");

		// Go to html and back, then peel off extra wrappers
		div.innerHTML = wrap[1] + html + wrap[2];

		// Move to the right depth
		while ( depth-- ) {
			div = div.lastChild;
		}		
		ret = div.childNodes;
		if ( fragment ) {
			for ( i = 0; ret[i]; i++ ) {
				fragment.appendChild( ret[i] );
			}
		}
		return ret;
    };
    
    
    /**
	 * 获取对象坐标
	 *
	 * @method getClientXY
	 * @memberOf dom
	 * 
	 * @param {HTMLElement} el
	 * @return Array [top,left]
	 * @type Array
	 */
	getClientXY = function(el) {
		var _t = 0,
			_l = 0;

		if (el) {
			//这里只检查document不够严谨, 在el被侵染置换(jQuery做了这么恶心的事情)
			//的情况下, el.getBoundingClientRect() 调用回挂掉
			if (document.documentElement.getBoundingClientRect && el.getBoundingClientRect) { // 顶IE的这个属性，获取对象到可视范围的距离。
				//现在firefox3，chrome2，opera9.63都支持这个属性。
				var box = el.getBoundingClientRect();
				var oDoc = el.ownerDocument;
				
				var _fix = J.browser.ie ? 2 : 0; //修正ie和firefox之间的2像素差异
				
				_t = box.top - _fix + getScrollTop(oDoc);
				_l = box.left - _fix + getScrollLeft(oDoc);
			} else {//这里只有safari执行。
				while (el.offsetParent) {
					_t += el.offsetTop;
					_l += el.offsetLeft;
					el = el.offsetParent;
				}
			}
		}
		return [_l, _t];
	};
	
	/**
	 * 设置dom坐标
	 * 
	 * @method setClientXY
	 * @memberOf dom
	 
	 * @param {HTMLElement} el
	 * @param {string|number} x 横坐标
	 * @param {string|number} y 纵坐标
	 */
	setClientXY = function(el, x, y) {
		x = parseInt(x) + getScrollLeft();
		y = parseInt(y) + getScrollTop();
		setXY(el, x, y);
	};

	/**
	 * 获取对象坐标
	 * 
	 * @method getXY
	 * @memberOf dom
	 *
	 * @param {HTMLElement} el
	 * @return Array [top,left]
	 * @type Array
	 */
	getXY = function(el) {
		var xy = getClientXY(el);

		xy[0] = xy[0] + getScrollLeft();
		xy[1] = xy[1] + getScrollTop();
		return xy;
	}

	/**
	 * 设置dom坐标
	 * @method setXY
	 * @memberOf dom
	 * 
	 * @param {HTMLElement} el
	 * @param {string|number} x 横坐标
	 * @param {string|number} y 纵坐标
	 */
	setXY = function(el, x, y) {
		var _ml = parseInt(getStyle(el, "marginLeft")) || 0;
		var _mt = parseInt(getStyle(el, "marginTop")) || 0;

		setStyle(el, "left", parseInt(x) - _ml + "px");
		setStyle(el, "top", parseInt(y) - _mt + "px");
	};
	
	/**
	 * 获取对象坐标
	 *
	 * @method getRelativeXY
	 * @memberOf dom
	 * 
	 * @param {HTMLElement} el
	 * @return Array [top,left]
	 * @type Array
	 */
	getRelativeXY = function(el, relativeEl) {
		var xyEl = getXY(el);
		var xyRelativeEl = getXY(relativeEl);
		var xy=[];
		
		xy[0] = xyEl[0] - xyRelativeEl[0];
		xy[1] = xyEl[1] - xyRelativeEl[1];
		return xy;
	}
	
	/**
	 * 获取选择的文本
	 *
	 * @method getSelectionText
	 * @memberOf dom
	 * 
	 * @param {Window} win
	 * @return {String} 返回选择的文本
	 */
	getSelectionText = function(win) {
		win = win || window;
		var doc = win.document;
		if (win.getSelection) {
			// This technique is the most likely to be standardized.
			// getSelection() returns a Selection object, which we do not document.
			return win.getSelection().toString();
		}else if (doc.getSelection) {
			// This is an older, simpler technique that returns a string
			return doc.getSelection();
		}else if (doc.selection) {
			// This is the IE-specific technique.
			// We do not document the IE selection property or TextRange objects.
			return doc.selection.createRange().text;
		}
	
	};


	/**
	 * FireFox 下获取 input 或者 textarea 中选中的文字
	 *
	 * @method getTextFieldSelection
	 * @memberOf dom
	 * 
	 * @param {HTMLElement} el
	 * @return {String} 返回选择的文本
	 */
	getTextFieldSelection = function(el) {
		if (el.selectionStart != undefined && el.selectionEnd != undefined) {
			var start = el.selectionStart;
			var end = el.selectionEnd;
			return el.value.substring(start, end);
		}else{
			return ""; // Not supported on this browser
		}
	
	};
	
	
	
	
	
	
    
    
    /*var scripts = tagName("script");
    for(var i=0; i<scripts.length; i++){
    	
    	if(scripts[i].getAttribute("hasJet")=="true"){
    		//J.out("hasJet: "+(scripts[i].getAttribute("hasJet")=="true"));
    		J.src = scripts[i].src;
    	}
    }
    if(!J.src){
    	J.src = scripts[scripts.length-1].src;
    }
	console.log(scripts.length);*/
	//J.filename = J.src.replace(/(.*\/){0,}([^\\]+).*/ig,"$2");
	//J.path = J.src.split(J.filename)[0];
	
	
	$D.getDoc = getDoc;
	
	$D.id = id;
	$D.name = name;
	$D.tagName = tagName;
	$D.getText = getText;
	$D.getAttributeByParent = getAttributeByParent;
	$D.node = node;
	$D.textNode = textNode;
	$D.setClass = setClass;
	$D.getClass = getClass;
	$D.hasClass = hasClass;
	
	$D.addClass = addClass;
	$D.removeClass = removeClass;
	$D.toggleClass = toggleClass;
	$D.replaceClass = replaceClass;
	
	$D.setStyle = setStyle;
	$D.getStyle = getStyle;
	
	$D.setCssText = setCssText;
	$D.getCssText = getCssText;
	$D.addCssText = addCssText;
	
	$D.show = show;
	$D.isShow = isShow;
	$D.recover = recover;
	$D.hide = hide;
	$D.remove = remove;
	$D.html = html;
	$D.text = text;
	$D.empty = empty;
	$D.prepend = prepend;
	$D.append = append;
	$D.html2dom = html2dom;
	
	
	$D.getScrollLeft = getScrollLeft;
	$D.getScrollTop = getScrollTop;
	$D.getScrollHeight = getScrollHeight;
	$D.getScrollWidth = getScrollWidth;
	
	$D.getClientHeight = getClientHeight;
	$D.getClientWidth = getClientWidth;
	
	$D.getOffsetHeight = getOffsetHeight;
	$D.getOffsetWidth = getOffsetWidth;
	
	$D.getClientXY = getClientXY;
	$D.setClientXY = setClientXY;
	
	$D.getXY = getXY;
	$D.setXY = setXY;
	$D.getRelativeXY = getRelativeXY;
	$D.getSelection = getSelection;
	$D.getSelectionText = getSelectionText;
	
	$D.getTextFieldSelection = getTextFieldSelection;
	
	$D.getDocumentElement = getDocumentElement;
	$D.getBodyElement = getBodyElement;
	
	
	
});

/**
 * 4.1 [dom part]: mini 选择器引擎
 */
Jet().$package(function(J){
	
	/**
	 * "mini" Selector Engine
	 * Copyright (c) 2009 James Padolsey
	 * -------------------------------------------------------
	 * Dual licensed under the MIT and GPL licenses.
	 *    - http://www.opensource.org/licenses/mit-license.php
	 *    - http://www.gnu.org/copyleft/gpl.html
	 * -------------------------------------------------------
	 * Version: 0.01 (BETA)
	 * 
	 * Usage:
	 * `tag`
	 * `tag > .className`
	 * `tag > tag`
	 * `#id > tag.className`
	 * `.className tag`
	 * `tag, tag, #id`
	 * `tag#id.className`
	 * `.className`
	 * `span > * > b` 
	 */
	var mini = (function(){
	    
	    var snack = /(?:[\w\-\\.#]+)+(?:\[\w+?=([\'"])?(?:\\\1|.)+?\1\])?|\*|>/ig,
	        exprClassName = /^(?:[\w\-_]+)?\.([\w\-_]+)/,
	        exprId = /^(?:[\w\-_]+)?#([\w\-_]+)/,
	        exprNodeName = /^([\w\*\-_]+)/,
	        na = [null,null];
	    
	    function _find(selector, context) {
	        
	        /**
	         * This is what you call via x()
	         * Starts everything off...
	         */
	        
	        context = context || document;
	        
	        var simple = /^[\w\-_#]+$/.test(selector);
	        
	        if (!simple && context.querySelectorAll) {
	            return realArray(context.querySelectorAll(selector));
	        }
	        
	        if (selector.indexOf(',') > -1) {
	            var split = selector.split(/,/g), ret = [], sIndex = 0, len = split.length;
	            for(; sIndex < len; ++sIndex) {
	                ret = ret.concat( _find(split[sIndex], context) );
	            }
	            return unique(ret);
	        }
	        
	        var parts = selector.match(snack),
	            part = parts.pop(),
	            id = (part.match(exprId) || na)[1],
	            className = !id && (part.match(exprClassName) || na)[1],
	            nodeName = !id && (part.match(exprNodeName) || na)[1],
	            collection;
	            
	        if (className && !nodeName && context.getElementsByClassName) {
	            
	            collection = realArray(context.getElementsByClassName(className));
	            
	        } else {
	            
	            collection = !id && realArray(context.getElementsByTagName(nodeName || '*'));
	            
	            if (className) {
	                collection = filterByAttr(collection, 'className', RegExp('(^|\\s)' + className + '(\\s|$)'));
	            }
	            
	            if (id) {
	                var byId = context.getElementById(id);
	                return byId?[byId]:[];
	            }
	        }
	        
	        return parts[0] && collection[0] ? filterParents(parts, collection) : collection;
	        
	    }
	    
	    function realArray(c) {
	        
	        /**
	         * Transforms a node collection into
	         * a real array
	         */
	        
	        try {
	            return Array.prototype.slice.call(c);
	        } catch(e) {
	            var ret = [], i = 0, len = c.length;
	            for (; i < len; ++i) {
	                ret[i] = c[i];
	            }
	            return ret;
	        }
	        
	    }
	    
	    function filterParents(selectorParts, collection, direct) {
	        
	        /**
	         * This is where the magic happens.
	         * Parents are stepped through (upwards) to
	         * see if they comply with the selector.
	         */
	        
	        var parentSelector = selectorParts.pop();
	        
	        if (parentSelector === '>') {
	            return filterParents(selectorParts, collection, true);
	        }
	        
	        var ret = [],
	            r = -1,
	            id = (parentSelector.match(exprId) || na)[1],
	            className = !id && (parentSelector.match(exprClassName) || na)[1],
	            nodeName = !id && (parentSelector.match(exprNodeName) || na)[1],
	            cIndex = -1,
	            node, parent,
	            matches;
	            
	        nodeName = nodeName && nodeName.toLowerCase();
	            
	        while ( (node = collection[++cIndex]) ) {
	            
	            parent = node.parentNode;
	            
	            do {
	                
	                matches = !nodeName || nodeName === '*' || nodeName === parent.nodeName.toLowerCase();
	                matches = matches && (!id || parent.id === id);
	                matches = matches && (!className || RegExp('(^|\\s)' + className + '(\\s|$)').test(parent.className));
	                
	                if (direct || matches) { break; }
	                
	            } while ( (parent = parent.parentNode) );
	            
	            if (matches) {
	                ret[++r] = node;
	            }
	        }
	        
	        return selectorParts[0] && ret[0] ? filterParents(selectorParts, ret) : ret;
	        
	    }
	    
	    
	    var unique = (function(){
	        
	        var uid = +new Date();
	                
	        var data = (function(){
	         
	            var n = 1;
	         
	            return function(elem) {
	         
	                var cacheIndex = elem[uid],
	                    nextCacheIndex = n++;
	         
	                if(!cacheIndex) {
	                    elem[uid] = nextCacheIndex;
	                    return true;
	                }
	         
	                return false;
	         
	            };
	         
	        })();
	        
	        return function(arr) {
	        
	            /**
	             * Returns a unique array
	             */
	            
	            var length = arr.length,
	                ret = [],
	                r = -1,
	                i = 0,
	                item;
	                
	            for (; i < length; ++i) {
	                item = arr[i];
	                if (data(item)) {
	                    ret[++r] = item;
	                }
	            }
	            
	            uid += 1;
	            
	            return ret;
	    
	        };
	    
	    })();
	    
	    function filterByAttr(collection, attr, regex) {
	        
	        /**
	         * Filters a collection by an attribute.
	         */
	        
	        var i = -1, node, r = -1, ret = [];
	        
	        while ( (node = collection[++i]) ) {
	            if (regex.test(node[attr])) {
	                ret[++r] = node;
	            }
	        }
	        
	        return ret;
	    }
	    
	    return _find;
	    
	})();

	/*
	 * ////////////////////////////////////////////////////////////////
	 * 
	 * Adapter to JET
	 * 
	 * ////////////////////////////////////////////////////////////////
	 */
	/**
	 * 一个据说比jq还快的筛选器，可以满足日常99%的筛选需要
	 * 
	 * @param {String} query string 筛选器语法
	 * @returns {Element} 返回筛选出的dom元素
	 * 
	 * @example
	 * //创建一个匿名package包：
	 * Jet().$package(function(J){
	 * 	//这时上下文对象this指向全局window对象
	 * 	var lists = J.dom.mini(".list");
	 * };
	 * 
	 */
	J.dom.mini = mini;

});